﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FlashlightRecorder.ViewModels;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework.Audio;
using System.Linq;
using System.Collections.Generic;
namespace AudioTester.WaveStreams
{
    public class WeakReferenceWithFactory<T>
    {
        public Func<T> Factory { get; set; }
        private WeakReference _core = new WeakReference(null);
        public T Reference
        {
            get
            {
                if (_core.Target == null)
                {
                    return (T)(_core.Target = (object)Factory());
                }
                else
                {
                    return (T)_core.Target;

                }
            }
            set
            {
                _core.Target = value;
            }
        }
    }


    public class Player_Model : DisposableHost, INotifyPropertyChanged
    {

        DynamicSoundEffectInstance _soundEffectInstance;
        public Player_Model()
        {
            WaveHeader wh = new WaveHeader() { SamplingFrequency = 44100, Channels = 2 };
            CreateChipList(wh);
            //_soundEffectInstance = new DynamicSoundEffectInstance(44100, AudioChannels.Stereo);

        }

        void _soundEffectInstance_BufferNeeded(object sender, EventArgs e)
        {
            Chip item;
            if ((item = this.SelectedItem) != null)
            {
                _soundEffectInstance.SubmitBuffer(item.GetData(this.Channels));
            }
        }

        private void CreateChipList(WaveHeader wh)
        {

            var hzList = new List<int>
            {
                10,
                20,                
                100,
                500,
                600,
                700,
                800,
                900,
                1000,
                1500,
                2000,
                3000,
                4000,
                5000,
                6000,
                7000,
                8000,
                9000,
                10000,
                12500,
                15000,
                17500,
                20000
            };

            var sinList = hzList
                .Select(hz =>
                     new
                     {
                         hz = hz,
                         dic = new Dictionary<Channels, WeakReferenceWithFactory<Byte[]>>()
                        {
                            { Channels.Right,new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateSinGenerator (hz,Channels.Right).Take(wh.BytesPerSecond).ToArray()}},
                            { Channels.Left, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateSinGenerator (hz,Channels.Left).Take(wh.BytesPerSecond).ToArray()}},
                            { Channels.Both, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateSinGenerator (hz,Channels.Both).Take(wh.BytesPerSecond).ToArray()} }                    
                        }
                     }
                )
                .Select(
                    item =>
                        new Chip
                        {
                            GetData = c => item.dic[c].Reference,
                            Name = string.Format("正弦波{0}Hz", item.hz),
                            IsChannelSelectable = true
                        });

            var tranList = hzList
                .Select(hz =>
                     new
                     {
                         hz = hz,
                         dic = new Dictionary<Channels, WeakReferenceWithFactory<Byte[]>>()
                                    {
                                        { Channels.Left, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateTriangularWaveGenerator (hz,Channels.Left).Take(wh.BytesPerSecond).ToArray()} },
                                        { Channels.Right,new WeakReferenceWithFactory<Byte[]> {Factory=()=>wh.CreateTriangularWaveGenerator (hz,Channels.Right).Take(wh.BytesPerSecond).ToArray()}},
                                        { Channels.Both, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateTriangularWaveGenerator (hz,Channels.Both).Take(wh.BytesPerSecond).ToArray()}}                     
                                    }
                     }
                )
            .Select(
                item =>
                    new Chip
                    {
                        GetData = c => item.dic[c].Reference,
                        Name = string.Format("三角波{0}Hz", item.hz),
                        IsChannelSelectable = true

                    });


            var sqList = hzList
                .Select(hz =>
                     new
                     {
                         hz = hz,
                         dic = new Dictionary<Channels, WeakReferenceWithFactory<Byte[]>>()
                                    {
                                        { Channels.Left, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateSquareWaveGenerator (hz,Channels.Left).Take(wh.BytesPerSecond).ToArray()}},
                                        { Channels.Right,new WeakReferenceWithFactory<Byte[]> { Factory=()=>wh.CreateSquareWaveGenerator (hz,Channels.Right).Take(wh.BytesPerSecond).ToArray()}},
                                        { Channels.Both, new WeakReferenceWithFactory<Byte[]> {Factory=()=> wh.CreateSquareWaveGenerator (hz,Channels.Both).Take(wh.BytesPerSecond).ToArray()}}                     
                                    }
                     }
                )
            .Select(
                item =>
                    new Chip
                    {
                        GetData = c => item.dic[c].Reference,
                        Name = string.Format("方波{0}Hz", item.hz),
                        IsChannelSelectable = true
                    });

            var wndic = new Dictionary<Channels, Byte[]>()
                                    {
                                        { Channels.Left,wh.CreateWhiteNoiseGenerator (Channels.Left).Take(wh.BytesPerSecond).ToArray()},
                                        { Channels.Right,wh.CreateWhiteNoiseGenerator (Channels.Right).Take(wh.BytesPerSecond).ToArray()},
                                        { Channels.Both,wh.CreateWhiteNoiseGenerator (Channels.Both).Take(wh.BytesPerSecond).ToArray()}                     
                                    };

            var allList = new List<Chip>()
            {
                new Chip{ Name="白噪声", GetData=c => wndic[c], IsChannelSelectable = true  }//,
                //new Chip{ Name="粉红噪声", GetData=c => wndic[c] },
                //new Chip{ Name="扫描正弦", GetData=c => wndic[c] }            
            };

            allList.AddRange(sinList);
            allList.AddRange(tranList);
            allList.AddRange(sqList);

            this.Chips = new ObservableCollection<Chip>(allList);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        bool _isPlaying;

        public bool IsPlaying
        {
            get { return _isPlaying; }
            set
            {

                if (value)
                {
                    if (_soundEffectInstance !=null)
                    {
                        _soundEffectInstance.BufferNeeded -= _soundEffectInstance_BufferNeeded;
                        _soundEffectInstance.Dispose();
                    }
                   
                    _soundEffectInstance = new DynamicSoundEffectInstance(44100, AudioChannels.Stereo);
                    _soundEffectInstance.BufferNeeded += new EventHandler<EventArgs>(_soundEffectInstance_BufferNeeded);
                    _soundEffectInstance.Play();

                }
                else
                {
                    this._soundEffectInstance.Stop();
                }
                _isPlaying = value; NotifyPropertyChanged("IsPlaying");
            }
        }

        Channels _channels;

        public Channels Channels
        {
            get
            {
                return

                    ((SelectedItem ?? new Chip()).IsChannelSelectable) ? _channels : Channels.Both;
            }
            set { _channels = value; NotifyPropertyChanged("Channels"); }
        }
        ObservableCollection<Chip> _chips;

        public ObservableCollection<Chip> Chips
        {
            get { return _chips; }
            set { _chips = value; NotifyPropertyChanged("Chips"); }
        }


        int _selectedIndex;

        public int SelectedIndex
        {
            get { return _selectedIndex; }
            set
            {
                _selectedIndex = value;
                NotifyPropertyChanged("SelectedIndex");
                NotifyPropertyChanged("SelectedItem");
            }
        }



        public Chip SelectedItem
        {
            get
            {

                if (SelectedIndex >= Chips.Count )
                {
                    SelectedIndex = 0;
                }

                return Chips[SelectedIndex];

            }

        }


    }

    public class Chip : DisposableHost, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        bool _isChannelSelectable;

        public bool IsChannelSelectable
        {
            get { return _isChannelSelectable; }
            set { _isChannelSelectable = value; NotifyPropertyChanged("IsChannelSelectable"); }
        }


        string _name;

        public string Name
        {
            get { return _name; }
            set { _name = value; NotifyPropertyChanged("Name"); }
        }


        Func<Channels, Byte[]> _getData;

        public Func<Channels, Byte[]> GetData
        {
            get { return _getData; }
            set { _getData = value; }
        }

    }



}
